package com.self.finance.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.anno.CreateCache;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.self.finance.mapper.CashWithdrawAuditRecordMapper;
import com.self.finance.model.CashRecharge;
import com.self.finance.model.CashRechargeAuditRecord;
import com.self.finance.model.CashWithdrawAuditRecord;
import com.self.finance.service.AccountService;
import com.self.member.dto.UserDto;
import com.self.member.feign.UserFeignClient;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.self.finance.model.CashWithdrawals;
import com.self.finance.mapper.CashWithdrawalsMapper;
import com.self.finance.service.CashWithdrawalsService;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

@Service
public class CashWithdrawalsServiceImpl extends ServiceImpl<CashWithdrawalsMapper, CashWithdrawals> implements CashWithdrawalsService{


    @Autowired
    private UserFeignClient userFeignClient;
    @CreateCache(name = "CASH_WITHDRAWALS_LOCK:")
    private Cache<String,String> lockCache;
    @Autowired
    private CashWithdrawAuditRecordMapper cashWithdrawAuditRecordMapper;
    @Autowired
    private AccountService accountService;

    @Override
    public Page<CashWithdrawals> findByPage(Page<CashWithdrawals> page, Long coinId, Long userId, String userName, String mobile, Byte status, String numMin, String numMax, String startTime, String endTime) {
        LambdaQueryWrapper<CashWithdrawals> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        Map<Long, UserDto> basicUsersByUsername = null;
        if (userId != null || StringUtils.isNotEmpty(userName) || StringUtils.isNotEmpty(mobile)){
            //查询用户名和真实姓名
            basicUsersByUsername = userFeignClient.getBasicUsersByUsername(userId == null ? null : Arrays.asList(userId), userName, mobile);
            if (!CollectionUtils.isEmpty(basicUsersByUsername)){
                lambdaQueryWrapper.in(!CollectionUtils.isEmpty(basicUsersByUsername.keySet()),CashWithdrawals::getUserId,basicUsersByUsername.keySet());
            }
        }
        lambdaQueryWrapper.eq(status != null,CashWithdrawals::getStatus,status)
                .between(!StringUtils.isEmpty(numMin) || !StringUtils.isEmpty(numMax),
                        CashWithdrawals::getNum,
                        StringUtils.isEmpty(numMin)? BigDecimal.ZERO:new BigDecimal(numMin),
                        StringUtils.isEmpty(numMax)? BigDecimal.ZERO:new BigDecimal(numMax))
                .between(!StringUtils.isEmpty(startTime) || !StringUtils.isEmpty(endTime),
                        CashWithdrawals::getCreated,
                        StringUtils.isEmpty(startTime)? DateUtil.beginOfDay(new Date()).toJdkDate() :DateUtil.parse(startTime).toJdkDate(),
                        StringUtils.isEmpty(endTime)? DateUtil.endOfDay(new Date()).toJdkDate() :DateUtil.parse(endTime).toJdkDate());

        Page<CashWithdrawals> rechargePage = page(page, lambdaQueryWrapper);
        if (rechargePage == null || CollectionUtils.isEmpty(rechargePage.getRecords())){
            return page;
        }
        if (CollectionUtils.isEmpty(basicUsersByUsername)){
            List<Long> collect = rechargePage.getRecords().stream().map(CashWithdrawals::getUserId).collect(Collectors.toList());
            basicUsersByUsername = userFeignClient.getBasicUsersByUsername(collect, null, null);
        }
        Map<Long, UserDto> finalBasicUsersByUsername = basicUsersByUsername;
        if (!CollectionUtils.isEmpty(basicUsersByUsername)){
            rechargePage.getRecords().forEach(x -> {
                UserDto userDto = finalBasicUsersByUsername.get(x.getUserId());
                if (userDto != null){
                    x.setUsername(userDto.getUsername());
                    x.setRealName(userDto.getRealName());
                }
            });
        }
        return rechargePage;
    }

    @Override
    public Page<CashWithdrawals> findCashWithdrawals(Page<CashWithdrawals> page, Long userId, Byte status) {
        return page(page,new LambdaQueryWrapper<CashWithdrawals>()
                .eq(CashWithdrawals::getUserId,userId)
                .eq(status!=null,CashWithdrawals::getStatus,status));
    }

    @Override
    public boolean updateStatus(CashWithdrawAuditRecord cashWithdrawAuditRecord) {
        long userId = Long.parseLong(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
        //审核成功后要进行充值，需要要用分布式锁
        boolean b = lockCache.tryLockAndRun(cashWithdrawAuditRecord.getId() + "", 300, TimeUnit.SECONDS, () -> {
            Long recordId = cashWithdrawAuditRecord.getId();
            CashWithdrawals cashWithdrawals = getById(recordId);
            Assert.notNull(cashWithdrawals,"提币记录不存在");
            Assert.isTrue(cashWithdrawals.getStatus() != 1,"充值记录已经审核通过");
            CashWithdrawAuditRecord auditRecord = new CashWithdrawAuditRecord();
            auditRecord.setAuditUserId(userId);
            auditRecord.setRemark(cashWithdrawAuditRecord.getRemark());
            auditRecord.setStatus(cashWithdrawAuditRecord.getStatus());
            Integer step = cashWithdrawAuditRecord.getStep()+1;
            auditRecord.setStep(step.byteValue());
            auditRecord.setOrderId(cashWithdrawals.getId());
            //保存审核记录
            int insert = cashWithdrawAuditRecordMapper.insert(auditRecord);
            Assert.isTrue(insert !=0,"保存审核记录失败");

            cashWithdrawals.setStatus(cashWithdrawAuditRecord.getStatus());
            cashWithdrawals.setAccountId(userId);
            cashWithdrawals.setRemark(cashWithdrawAuditRecord.getRemark());
            cashWithdrawals.setLastTime(new Date());
            boolean update = updateById(cashWithdrawals);
            if (update){//审核通过，扣减金额
                boolean flag = accountService.decreaseAccountAmount(userId,cashWithdrawals.getUserId(),cashWithdrawals.getCoinId(),cashWithdrawals.getId(), cashWithdrawals.getNum(),
                        cashWithdrawals.getFee(),"withdrawals_out",Byte.parseByte("2"),cashWithdrawals.getRemark());
            }
        });
        return b;
    }
}
